package arithmetic;

import utils.NumUtil;

/**
 * @Author: Jie
 * @Date: 2019/3/8 15:10
 * @Function : C语言 1 true  0 false
 *  &    0 & 1 = 0
 *  |    0 | 1 = 1
 *  ^    0 ^ 1 = 1    相同为 0 ，不同 1
 *  `    ~1 = 0
 *  <<    左移
 *  >>    右移
 *
 *  原码 ：一个整数，按照【绝对值】大小转换成的二进制数，成为 原码。
 *  反码 ：原码按位取反。
 *
 *  正负数用【补码】来表示。
 *  正数 的【补码】就是【原码】
 *  负数 的【补码】就是【原码】的【反码】再加 1 。
 *
 *  -1：int 4字节32位
 *  1的原码：00000000 00000000 00000000 00000001
 * 反码：    11111111 11111111 11111111 11111110
 * 补码：    11111111 11111111 11111111 11111111
 *
 * 判断正负：
 * 看计算机  是否存储【符号】
 * 无符号存储 ： 都是正数。
 * 有符号存储 ： 则为 【补码】存储
 * 看其最高位，最高位为 0 ，正数，反之，为负数。
 *
 *
 * 32位int类型整数为 -2147483648 到 2147483647
 *
 * -2147483647：
 * 原码为1111 1111 1111 1111 1111 1111 1111 1111，
 * 反码为1000 0000 0000 0000 0000 0000 0000 0000，
 * 补码为1000 0000 0000 0000 0000 0000 0000 0001
 * 所以最小的负数是-2147483647吗？错，不是。
 * ---------------------
 * 在二进制中，0有两种表方法。
 * +0的原码为0000 0000 0000 0000 0000 0000 0000 0000，
 * -0的原码为1000 0000 0000 0000 0000 0000 0000 0000，
 *
 * 因为0只需要一个，所以把-0拿来当做一个最小的数-2147483648。
 * -2147483648的补码表示为1000 0000 0000 0000 0000 0000 0000 0000，在32位没有原码。
 *
 * 注意，这个补码并不是真正的补码，真正的补码是1 1000 0000 0000 0000 0000 0000 0000 0000，溢出。
 * 注意，2147483648 正数                         1000 0000 0000 0000 0000 0000 0000 0000。
 *
 *
 * 在计算机中是【不存在正负零之分】的．补码只不过是用来表示带符号数而已．补码的原则是：
 * 正数的补码是其本身，也就是原码．
 * 负数的补码是各位取反后加1．也就是其反码加1．
 * +0的补码就是其原码，也就是说是0000 0000而已（对于8位来说）
 * -0的补码是其反码加1，其反码是1111 1111，当然，其反码加1后就是溢出一个进位后，仍然是0000 0000.
 *
 *
 * <<      :     左移运算符，num << 1,相当于num乘以2
 *
 * >>      :     右移运算符，num >> 1,相当于num除以2
 * 	表示右移，如果该数为正，则高位补0，若为负数，则高位补1；
 * >>>    :     无符号右移，忽略符号位，空位都以0补齐
 * 	表示无符号右移，也叫逻辑右移，即若该数为正，则高位补0，而若该数为负数，则右移后高位同样补0。
 *
 */
public class A_20_Binary {
    public static void main(String[] args) {
        int x = 0b0111;
        System.out.println(x ^ 0);
        System.out.println( ~0);
        System.out.println(x ^ (~0));
        System.out.println(x ^ (~x));

        System.out.println(" x ..."+ x);
        System.out.println("判断奇偶:  x & 1 == 1 or x & 1 == 0 ..."+ ( x & 1));
        System.out.println("清零最低位: x = x & (x-1) ..."+ ( x & (x-1)));
        System.out.println("得到最低位的1:  x & -x  ..."+ ( x & -x));
        System.out.println(" -x ..."+ (~x+1));
        System.out.println(" -x ..."+ ( Integer.toBinaryString(~x+1)));
        System.out.println(" x ..."+ ~((~x+1)-1));

        long y = 2147483648L;
        System.out.println(" int ..."+ ( Integer.toBinaryString(Integer.MAX_VALUE)));//31 位省略了首位 0
        System.out.println(" int ..."+ ( Integer.toBinaryString(Integer.MIN_VALUE)));//32 位
        System.out.println(" int ..."+ ( Long.toBinaryString(y)));
        System.out.println(" int ..."+ ( Long.toBinaryString(~y+1)));

        int num = 0xffffffff;

        System.out.println(" MAX_VALUE ..."+ Integer.MAX_VALUE +" length=="+NumUtil.numOfDigits(Integer.MAX_VALUE));
        System.out.println("0xffffffff ..."+ num + " length=="+NumUtil.numOfDigits(num));
        System.out.println(" MAX_VALUE ..."+ Long.toBinaryString(Integer.MAX_VALUE)+"  length=="+Long.toBinaryString(Integer.MAX_VALUE).length());
        System.out.println("0xffffffff ..."+ Long.toBinaryString(num)+ "  length=="+Long.toBinaryString(num).length());

        System.out.println("Integer.MAX_VALUE & Integer.MIN_VALUE=="+(Integer.MAX_VALUE & Integer.MAX_VALUE-1));
        System.out.println("Integer.MAX_VALUE & Integer.MIN_VALUE=="+(Integer.MAX_VALUE & Integer.MIN_VALUE));


        System.out.println("A_20_Binary:main:--------------------------------------------------------------------");
        // 都是 0
        System.out.println("0 : number >>> 1 res:"+(0 >>> 1));// 2147483643
        System.out.println("0 : number >> 1 res:"+(0 >> 1));// 2147483643

        //>>> 错误。>> 正确。
        System.out.println("-10 : number >>> 1 res:"+(-10 >>> 1));// 2147483643
        System.out.println("-10 : number >> 1 res:"+(-10 >> 1));// -5
        System.out.println(" 10 : number >>> 1 res:"+(10 >>> 1));// 5
        System.out.println(" 10 : number >> 1 res:"+(10 >> 1));// 5

        //>>> 错误。>> 正确。
        System.out.println("-10 : number >>> 2 res:"+(-10 >>> 2));// 1073741821
        System.out.println("-10 : number >> 2 res:"+(-10 >> 2));// -3
        System.out.println(" 10 : number >>> 2 res:"+(10 >>> 2));// 2
        System.out.println(" 10 : number >> 2 res:"+(10 >> 2));// 2

        int number = -10;
        // 原始数二进制
        printNumtoBinarry(number);
        number = number << 1;
        // 左移一位
        printNumtoBinarry(number);
        number = number >> 1;
        // 右移一位
        printNumtoBinarry(number);
        //无符号 右移2位
        number = number >>> 2;
        printNumtoBinarry(number);




        int a = -1 << 1;
        System.out.println("(-1<<1):"+a);
        printNumtoBinarry(-1);
        printNumtoBinarry(a);

        System.out.println("-8 origin:");
        printNumtoBinarry(-8);
        int b = -8 >> 1;
        System.out.println("(-8>>1):"+b);
        printNumtoBinarry(b);

        int c = -8 >>> 1;
        System.out.println("(-8>>>1):"+c);//TODO 首位是0，所以结果为正数。2147483644
        printNumtoBinarry(c);

    }

    /**
     * 输出一个int的二进制数
     * @param num
     */
    private static void printNumtoBinarry(int num) {
        System.out.println(Integer.toBinaryString(num));
    }
}
